package handler

import (
	"net/http"
	"strconv"

	"gitee.com/thewalkers/refactoring-code/model"
	"gitee.com/thewalkers/refactoring-code/model/apperrors"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

const (
	createEmployeeSuccess = "添加员工成功"
	getEmployeeSuccess    = "获取员工成功"
	updateEmployeeSuccess = "修改员工信息成功"
)

type createEmployeeParams struct {
	Name    string `json:"employee_name" binding:"required"`
	Address string `json:"employee_address" binding:"required"`
}

// Create Employee
func (h *Handler) CreateEmployee(ctx *gin.Context) {

	var req createEmployeeParams

	// Bind incoming json to struct and check for validation errors
	if ok := bindData(ctx, &req); !ok {
		return
	}

	e := &model.Employee{
		Name:    req.Name,
		Address: req.Address,
	}

	// service layer handle this
	err := h.EmployeeService.Create(ctx, e)
	if err != nil {
		zap.L().Error("service failed to create employee", zap.Error(err))
		ctx.JSON(apperrors.Status(err), gin.H{
			"error": err,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg": createEmployeeSuccess,
	})
}

// GetEMployee
func (h *Handler) GetEmployeeByID(ctx *gin.Context) {
	// 1. 从 URL 中获取员工的 id
	id := ctx.Param("id")

	employeeID, err := strconv.ParseInt(id, 10, 64)
	if err != nil {
		zap.L().Error("handler failed to parse parameters", zap.Error(err))

		e := apperrors.NewBadRequest(err.Error())

		ctx.JSON(e.Status(), gin.H{
			"error": e.Message,
		})
		return
	}

	employee, err := h.EmployeeService.Get(ctx, employeeID)
	if err != nil {
		zap.L().Error("service failed to get employee", zap.Error(err))
		ctx.JSON(apperrors.Status(err), gin.H{
			"error": err,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg":      getEmployeeSuccess,
		"employee": employee,
	})
}

type updateEmployeeNameParams struct {
	ID      int64  `json:"employee_id" binding:"required"`
	Name    string `json:"employee_name" binding:"required"`
	Address string `json:"employee_address" binding:"required"`
}

// UpdateEmployee
func (h *Handler) UpdateEmployee(ctx *gin.Context) {
	var req updateEmployeeNameParams

	if ok := bindData(ctx, &req); !ok {
		return
	}

	e := &model.Employee{
		ID:      req.ID,
		Name:    req.Name,
		Address: req.Address,
	}

	if err := h.EmployeeService.UpdateByID(ctx, e); err != nil {
		zap.L().Error("server updateByID failed", zap.Error(err))
		e := apperrors.NewInternal()
		ctx.JSON(e.Status(), gin.H{
			"msg": e.Message,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg": updateEmployeeSuccess,
	})
}

type changeAddressTransactionParams struct {
	ID      int64  `json:"employee_id" binding:"required"`
	Address string `json:"employee_address" binding:"required"`
}

func (h *Handler) ChangeAddressTransaction(ctx *gin.Context) {
	var req changeAddressTransactionParams

	if ok := bindData(ctx, &req); !ok {
		return
	}

	e, err := h.EmployeeService.Get(ctx, req.ID)
	if err != nil {
		zap.L().Error("server Get Employee failed", zap.Error(err))
		er := apperrors.NewNotFound("employee", strconv.Itoa(int(req.ID)))
		ctx.JSON(er.Status(), gin.H{
			"msg": er.Message,
		})
		return
	}

	e.Address = req.Address

	if err := h.EmployeeService.UpdateByID(ctx, e); err != nil {
		zap.L().Error("server updateByID failed", zap.Error(err))
		e := apperrors.NewInternal()
		ctx.JSON(e.Status(), gin.H{
			"msg": e.Message,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg": updateEmployeeSuccess,
	})
}

type changeNameTransactionParams struct {
	ID   int64  `json:"employee_id" binding:"required"`
	Name string `json:"employee_name" binding:"required"`
}

func (h *Handler) ChangeNameTransaction(ctx *gin.Context) {
	var req changeNameTransactionParams

	if ok := bindData(ctx, &req); !ok {
		return
	}

	e, err := h.EmployeeService.Get(ctx, req.ID)
	if err != nil {
		zap.L().Error("server Get Employee failed", zap.Error(err))
		er := apperrors.NewNotFound("employee", strconv.Itoa(int(req.ID)))
		ctx.JSON(er.Status(), gin.H{
			"msg": er.Message,
		})
		return
	}

	e.Name = req.Name

	if err := h.EmployeeService.UpdateByID(ctx, e); err != nil {
		zap.L().Error("server updateByID failed", zap.Error(err))
		e := apperrors.NewInternal()
		ctx.JSON(e.Status(), gin.H{
			"msg": e.Message,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg": updateEmployeeSuccess,
	})
}
